﻿using System;
using System.IO;
using System.Linq;
using System.ServiceModel.Syndication;
using System.Xml;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TestProject.Assessment.Data;
using SoftwareApproach.TestingExtensions;

namespace TestProject.Assessment
{
    public static class RssAssert
    {
        public static SyndicationFeed ShouldBeRss20(this string source)
        {
            var rss = new Rss20FeedFormatter();
            using (var stream = new StringReader(source))
            {
                XmlReader xmlReader = XmlReader.Create(stream);
                Assert.IsTrue(rss.CanRead(xmlReader));
                rss.ReadFrom(xmlReader);
                xmlReader.Close();
            }
            return rss.Feed;
        }

        public static SyndicationFeed WithNumberOfElementsEqual(this SyndicationFeed feed, int expected)
        {
            Assert.AreEqual(expected, feed.Items.Count());
            return feed;
        }

        public static SyndicationFeed LastUpdateTimeEqual(this SyndicationFeed feed, DateTime expected)
        {
            var absoluteDiffSeconds = Math.Abs((feed.LastUpdatedTime - expected).TotalSeconds);
            Assert.IsTrue(absoluteDiffSeconds < 1.0, "LastUpdateTime is differ from expected");
            return feed;
        }
    }

    [TestClass]
    public class RssAssertTest
    {
        [TestMethod]
        public void ShouldBeRss20_CorrectRss20_ShouldNotThrowException()
        {
            //arrange
            var target = RssResource.DefaultRss2;

            //action

            //assert
            target.ShouldBeRss20();
        }

        [TestMethod]
        [ExpectedException(typeof(AssertFailedException))]
        public void ShouldBeRss20_GoodXmlButNotRss20_ShouldThrowException()
        {
            //arrange
            var target = RssResource.NotRss20;

            //action

            //assert
            target.ShouldBeRss20();
        }

        [TestMethod]
        public void ShouldBeRss20_CorrectRss20_ShouldReturnInstanceOfSyndicationFeed()
        {
            //arrange
            var target = RssResource.DefaultRss2;

            //action
            var result = target.ShouldBeRss20();

            //assert
            result.ShouldBeOfType(typeof(SyndicationFeed));
        }

        [TestMethod]
        public void WithNumberOfElementsEqual_FeedWith2Elements_ShouldNotThrowException()
        {
            //arrange
            var target = new SyndicationFeed { Items = new SyndicationItem[2] };

            //action
            //assert
            target.WithNumberOfElementsEqual(2);
        }

        [TestMethod]
        public void LastUpdateTimeEqual_FeedWithLastUpdateTimeSetToNow_ShouldNotThrowException()
        {
            //arrange
            var now = new DateTime(2010, 01, 01, 0, 0, 0, 0);
            var target = new SyndicationFeed { LastUpdatedTime = now };

            //action
            //assert
            target.LastUpdateTimeEqual(now.AddMilliseconds(150));
        }

        [TestMethod]
        [ExpectedException(typeof(AssertFailedException))]
        public void LastUpdateTimeEqual_FeedWithLastUpdateTimeSetToNowPlus1Second_ShouldThrowException()
        {
            //arrange
            var now = new DateTime(2010, 01, 01, 0, 0, 0, 0);
            var target = new SyndicationFeed { LastUpdatedTime = now };

            //action
            //assert
            target.LastUpdateTimeEqual(now.AddMilliseconds(1001));
        }
    }
}